package cz.stv.pecinovsky.město;

import cz.stv.pecinovsky.správceplátna.SprávcePlátna;

import cz.stv.pecinovsky.utility.Barva;
import cz.stv.pecinovsky.utility.Pozice;
import cz.stv.pecinovsky.utility.Směr8;


/*******************************************************************************
 * Instance třídy {@code TovárnaNaKola} představují továrny, které jsou schopny
 * na požádání "vyrobit" obdélníkový okruh.
 *
 * @author  Rudolf PECINOVSKÝ
 * @version 1.10.2678 — 2011-10-27
 */
public class TovárnaNaKola implements ITovárnaOkruhů
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    /** Správce plátna, na němž bude cesta zobrazena. */
    SprávcePlátna SP = SprávcePlátna.getInstance();



//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================
//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

    /** Políčková šířka okruhů, tj. počet zabraných sloupců. */
    private final int sloupců;

    /** Políčková výška okruhů, tj. počet zabraných řádků. */
    private final int řádků;

    /** Směr, která se vyráží z výchozí pozice. */
    private final Směr8 směr;



//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================

     /** Implicitní barva vytvářených okruhů. */
     private Barva implicitníBarva = Barva.ČERNÁ;



//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================
//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Vytvoří nový obdélníkový okruh se zadanou počtem polí na šířku i výšku
     * a se zadaným směrem, jímž se vyráží z vvýchozí pozice, která je vždy
     * v levém horním rohu vytvořeného okruhu.
     * 
     * @param sloupců Políčková šířka okruhů, tj. počet zabraných sloupců
     * @param řádků   Políčková výška okruhů, tj. počet zabraných řádků
     * @param směr    Směr, která se vyráží z výchozí pozice, má smysl pouze
     *                {@link Směr8.VÝCHOD} nebo {@link Směr8.JIH}
     */
    public TovárnaNaKola(int sloupců, int řádků, Směr8 směr)
    {
        this.sloupců = sloupců;
        this.řádků   = řádků;
        this.směr    = směr;
    }



//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================

    /***************************************************************************
     * Nastaví implicitní barvu vytvářených okruhů.
     *
     * @param barva Nastavovaná implicitní barva
     * @return Dříve nastavená implicitní barva
     */
    @Override
    public Barva setImplicitníBarva(Barva barva)
    {
        Barva stará     = implicitníBarva;
        implicitníBarva = barva;
        return stará;
    }


    /***************************************************************************
     * Vrátí počet sloupců, které daný okruh zabere.
     *
     * @return Počet sloupců okruhu
     */
    public int getSloupců()
    {
        return sloupců;
    }


    /***************************************************************************
     * Vrátí počet řádků, které daný okruh zabere.
     *
     * @return Počet řádků okruhu
     */
    public int getŘádků()
    {
        return řádků;
    }



//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================

    /***************************************************************************
     * Vytvoří okruh implicitní barvy se startovním polem na zadané pozici.
     *
     * @param startPozice Pozice startovního pole vytvářeného okruhu
     * @return Vytvořený okruh
     */
    @Override
    public Okruh vytvořOkruh(Pozice startPozice)
    {
        return vytvořOkruh(startPozice, implicitníBarva);
    }


    /***************************************************************************
     * Vytvoří okruh zadané barvy se startovním polem na zadané pozici.
     *
     * @param startPozice Pozice startovního pole vytvářeného okruhu
     * @param barva       Barva vytvářeného okruhu
     * @return Vytvořený okruh
     */
    @Override
    public Okruh vytvořOkruh(Pozice startPozice, Barva barva)
    {
        StavitelOkruhů stavitel = new StavitelOkruhů(startPozice, barva);
        stavitel.zahajNa(směr);
        if (směr == Směr8.JIH) {
            dotvořOkruh(stavitel, řádků-1, sloupců, řádků, sloupců-1);
        }
        else {
            dotvořOkruh(stavitel, sloupců-1, řádků, sloupců, řádků-1);
        }
        return stavitel.getOkruh();
    }


    /***************************************************************************
     * Prostřednictvím zadaného stavitele dotvoří okruh zadaných rozměrů
     * přičemž směr pohybu po vytvářeném okruhu je odvozen z atributu
     * {@link #směr}.
     *
     * @param stavitel Stavitel, který začal stavět zadaný okruh
     * @param rozměry  Počet průběžných polí, která se mají položit
     *                 v jednotlivých směrech
     */
    private void dotvořOkruh(StavitelOkruhů stavitel, int... rozměry)
    {
        if (rozměry.length != 4) {
            throw new IllegalArgumentException(
                    "\nMusí být zadány právě čtyři rozměry");
        }
        Směr8 aktSměr = směr;
        for (int rozměr : rozměry) {
            for (int i=1;   i < rozměr;   i++) {
                stavitel.pokračujNa(aktSměr);
            }
            if (směr == Směr8.JIH) {
                aktSměr = aktSměr.vlevoVbok();
            } else {
                aktSměr = aktSměr.vpravoVbok();
            }
        }
        //Musím směr otočit zpět, protože ještě nezahýbám
        if (směr == Směr8.JIH) {
            aktSměr = aktSměr.vpravoVbok();
        } else {
            aktSměr = aktSměr.vlevoVbok();
        }
        stavitel.uzavřiNa(aktSměr);
    }



//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTY A METODA MAIN =======================================================
//
//    /***************************************************************************
//     * Testovací metoda.
//     */
//    public static void test()
//    {
//        TovárnaNaKola inst = new TovárnaNaKola();
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main( String[] args )  {  test();  }
}

